﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Prism.Events;
using Models;
using Newtonsoft.Json;
using System.Collections.Concurrent;

namespace Server.Common
{
    public class LogEvent : PubSubEvent<string> { }

    public static class Comm
    {
        #region 全局对象

        public static Taxhui.Utils.DBUtils.SQLiteDB.DB DB;
        public static Dictionary<string, SessionModel> Onlines = new Dictionary<string, SessionModel>();
        public static Window Shell;
        public static Dictionary<Cmd, Func<Dictionary<string, object>, RetModel>> BLLHandle = new Dictionary<Cmd, Func<Dictionary<string, object>, RetModel>>();
        public static ConfigModel Cfg = new ConfigModel();

        #endregion 全局对象

        #region 初始BLL字典

        private static void InitBllDc()
        {
            BLLHandle[Cmd.Bill_AddSaleBill] = BLL.BillBLL.AddSaleBill;
            BLLHandle[Cmd.Bill_GetCodeInfo] = BLL.BillBLL.GetCodeInfo;
            BLLHandle[Cmd.Bill_AddChargeBill] = BLL.BillBLL.AddChargeBill;
            BLLHandle[Cmd.Bill_GetProSummary] = BLL.BillBLL.GetProSummary;
            BLLHandle[Cmd.Bill_GetChargeSummary] = BLL.BillBLL.GetChargeSummary;
            BLLHandle[Cmd.Bill_GetSaleDetail] = BLL.BillBLL.GetSaleDetail;
            BLLHandle[Cmd.Bill_GetSaleSummary] = BLL.BillBLL.GetSaleSummary;
            BLLHandle[Cmd.Bill_GetChargeDetail] = BLL.BillBLL.GetChargeDetail;
            BLLHandle[Cmd.Bill_GetPointBill] = BLL.BillBLL.GetPointBill;
            BLLHandle[Cmd.Bill_GetPointBillList] = BLL.BillBLL.GetPointBillList;
            BLLHandle[Cmd.Bill_SavePointBill] = BLL.BillBLL.SavePointBill;

            BLLHandle[Cmd.Code_AddCode] = BLL.CodeBLL.AddCode;
            BLLHandle[Cmd.Code_AddCodeBatch] = BLL.CodeBLL.AddCodeBatch;
            BLLHandle[Cmd.Code_CancelCode] = BLL.CodeBLL.CancelCode;
            BLLHandle[Cmd.Code_GetCodeInfo] = BLL.CodeBLL.GetCodeInfo;
            BLLHandle[Cmd.Code_GetCodeList] = BLL.CodeBLL.GetCodeList;
            BLLHandle[Cmd.Code_GetCodeStatusInfo] = BLL.CodeBLL.GetCodeStatus;
            BLLHandle[Cmd.Code_GetStatusList] = BLL.CodeBLL.GetStatusList;

            BLLHandle[Cmd.Log_ClearLog] = BLL.LogBLL.ClearLog;
            BLLHandle[Cmd.Log_GetLog] = BLL.LogBLL.GetLog;
            BLLHandle[Cmd.Log_GetLogList] = BLL.LogBLL.GetLogList;
            BLLHandle[Cmd.Log_Write] = BLL.LogBLL.Write;

            BLLHandle[Cmd.Cust_Cate_AddCate] = BLL.CustomBLL.AddCate;
            BLLHandle[Cmd.Cust_Cate_EditCate] = BLL.CustomBLL.EditCate;
            BLLHandle[Cmd.Cust_Cate_DelCate] = BLL.CustomBLL.DelCate;
            BLLHandle[Cmd.Cust_Cate_GetCateInfo] = BLL.CustomBLL.GetCateInfo;
            BLLHandle[Cmd.Cust_Cate_GetCateList] = BLL.CustomBLL.GetCateList;
            BLLHandle[Cmd.Cust_AddCust] = BLL.CustomBLL.AddCust;
            BLLHandle[Cmd.Cust_EditCust] = BLL.CustomBLL.EditCustom;
            BLLHandle[Cmd.Cust_EnableCust] = BLL.CustomBLL.EnableCustom;
            BLLHandle[Cmd.Cust_DisableCust] = BLL.CustomBLL.DisableCustom;
            BLLHandle[Cmd.Cust_GetCustInfo] = BLL.CustomBLL.GetCustInfo;
            BLLHandle[Cmd.Cust_GetCustList] = BLL.CustomBLL.GetCustList;
            BLLHandle[Cmd.Cust_UpdateCustSummary] = BLL.CustomBLL.UpdateCustSummary;

            BLLHandle[Cmd.Pro_AddProduct] = BLL.ProBLL.AddPro;
            BLLHandle[Cmd.Pro_DisablePro] = BLL.ProBLL.DisablePro;
            BLLHandle[Cmd.Pro_EnablePro] = BLL.ProBLL.EnablePro;
            BLLHandle[Cmd.Pro_EditPro] = BLL.ProBLL.EditPro;
            BLLHandle[Cmd.Pro_GetProInfo] = BLL.ProBLL.GetProInfo;
            BLLHandle[Cmd.Pro_GetProList] = BLL.ProBLL.GetProList;
            BLLHandle[Cmd.Pro_UpdatePrice] = BLL.ProBLL.UpdatePrice;

            BLLHandle[Cmd.Usr_AddUser] = BLL.UserBLL.AddUser;
            BLLHandle[Cmd.Usr_EditUser] = BLL.UserBLL.EditUser;
            BLLHandle[Cmd.Usr_EnableUser] = BLL.UserBLL.EnableUser;
            BLLHandle[Cmd.Usr_DisableUser] = BLL.UserBLL.DisableUser;
            BLLHandle[Cmd.Usr_EditPass] = BLL.UserBLL.EditPass;
            BLLHandle[Cmd.Usr_GetUserInfo] = BLL.UserBLL.GetUserInfo;
            BLLHandle[Cmd.Usr_GetUserList] = BLL.UserBLL.GetUserList;
            BLLHandle[Cmd.Usr_Login] = BLL.UserBLL.Login;
            BLLHandle[Cmd.Usr_HeartBeat] = BLL.UserBLL.HeartBeat;
        }

        #endregion 初始BLL字典

        #region 写日志到界面

        public delegate void WriteLogHandler(string s);

        public static event WriteLogHandler ErrPushed;

        #endregion 写日志到界面

        #region 主界面关闭事件

        public delegate void FormClosingEventHandler(object sender, System.ComponentModel.CancelEventArgs e);

        public static event FormClosingEventHandler FormClosing;

        #endregion 主界面关闭事件

        #region 处理数据事件

        public static Dictionary<Cmd, BLLHandler> HandleDc = new Dictionary<Cmd, BLLHandler>();

        public delegate object BLLHandler(Dictionary<string, object> dc);

        #endregion 处理数据事件

        private static readonly ConcurrentDictionary<Type, Func<object, object>> CvtDc = new ConcurrentDictionary<Type, Func<object, object>>();

        #region 构造函数

        static Comm()
        {
            InitCvr();
            InitParamResolveDc();
            InitDB();
            InitBllDc();
            Task.Run(CheckOnlineList);
        }

        #endregion 构造函数

        #region 初始数据库连接

        public static void InitDB()
        {
            if (DB != null)
                return;
            try
            {
                Taxhui.Utils.UserModel.SqliteDbConfig dbCfg = new Taxhui.Utils.UserModel.SqliteDbConfig()
                {
                    DBpath = Environment.CurrentDirectory + @"\Data.db",
                    Password = "Qigh,.98"
                };
                DB = new Taxhui.Utils.DBUtils.SQLiteDB.DB(dbCfg);
            }
            catch (Exception)
            {
                DB = null;
                throw;
            }
        }

        #endregion 初始数据库连接

        #region 检查在线列表

        private static void CheckOnlineList()
        {
            while (true)
            {
                try
                {
                    foreach (var itm in Onlines)
                    {
                        CheckOnlineTimeout(itm.Value, itm.Key);
                    }
                    System.Threading.Thread.Sleep(10000);
                }
                catch (Exception)
                {
                }
            }
        }

        #endregion 检查在线列表

        #region 增加一个在线

        public static void AddOnline(SessionModel sm)
        {
            if (null == sm)
                return;
            Onlines[sm.SessionId] = sm;
        }

        #endregion 增加一个在线

        #region 查询在线状态

        public static SessionModel GetOnlineInfo(string sessionId)
        {
            if (!Onlines.Keys.Contains(sessionId))
                return null;
            var ol = Onlines[sessionId];
            if (ol.UpdateTime < DateTime.Now.AddMinutes(-5))
            {
                Onlines.Remove(sessionId);
                return null;
            }
            return Onlines[sessionId];
        }

        #endregion 查询在线状态

        #region 检查在线超时

        private static void CheckOnlineTimeout(SessionModel sess, string key)
        {
            if (sess.UpdateTime < DateTime.Now.AddMinutes(-5))
                RemoveOnline(key);
        }

        #endregion 检查在线超时

        #region 移除在线

        public static void RemoveOnline(string sessionId)
        {
            if (Onlines.Keys.Contains(sessionId))
                Onlines.Remove(sessionId);
        }

        #endregion 移除在线

        #region 清除在线列表

        public static void ClearOnline()
        {
            Onlines.Clear();
        }

        #endregion 清除在线列表

        #region Dr转换类型

        public static T Cdr<T>(DataRow dr, string name)
        {
            return dr is null ? default : (T)CvtDc[typeof(T)](dr[name]);
        }

        private static void InitCvr()
        {
            CvtDc[typeof(string)] = CvtToString;
            CvtDc[typeof(decimal)] = CvtToDecimal;
            CvtDc[typeof(int)] = CvtToInt;
            CvtDc[typeof(long)] = CvtToLong;
            CvtDc[typeof(byte)] = CvtToByte;
            CvtDc[typeof(bool)] = CvtToBool;
            CvtDc[typeof(double)] = CvtToDouble;
            CvtDc[typeof(float)] = CvtToFloat;
            CvtDc[typeof(DateTime)] = CvtToDate;
        }

        private static object CvtToString(object obj)
        {
            return obj?.ToString();
        }

        private static object CvtToDecimal(object obj)
        {
            return Convert.ToDecimal(obj);
        }

        private static object CvtToInt(object obj)
        {
            return Convert.ToInt32(obj);
        }

        private static object CvtToLong(object obj)
        {
            return Convert.ToInt64(obj);
        }

        private static object CvtToDouble(object obj)
        {
            return Convert.ToDouble(obj);
        }

        private static object CvtToFloat(object obj)
        {
            return Convert.ToSingle(obj);
        }

        private static object CvtToDate(object obj)
        {
            return Convert.ToDateTime(obj);
        }

        private static object CvtToByte(object obj)
        {
            return Convert.ToByte(obj);
        }

        private static object CvtToBool(object obj)
        {
            return Convert.ToBoolean(obj);
        }

        #endregion Dr转换类型

        #region 错误消息事件

        public static void RaiseWriteText(string s)
        {
            ErrPushed?.Invoke(s);
        }

        #endregion 错误消息事件

        #region 窗口关闭事件

        public static void RaiseMainFormClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            FormClosing?.Invoke(sender, e);
        }

        #endregion 窗口关闭事件

        #region 字典值转换

        private static readonly Dictionary<Type, Func<Dictionary<string, object>, string, object, object>> paramDC =
            new Dictionary<Type, Func<Dictionary<string, object>, string, object, object>>();

        private static void InitParamResolveDc()
        {
            paramDC[typeof(int)] = CTInt;
            paramDC[typeof(long)] = CTLong;
            paramDC[typeof(string)] = CTString;
            paramDC[typeof(float)] = CTFloat;
            paramDC[typeof(double)] = CTDouble;
            paramDC[typeof(decimal)] = CTDecimal;
            paramDC[typeof(byte)] = CTByte;
            paramDC[typeof(bool)] = CTBool;
            paramDC[typeof(DateTime)] = CTDateTime;
        }

        public static T ResolveParam<T>(Dictionary<string, object> dc, string name, T defVal)
        {
            return (T)paramDC[typeof(T)](dc, name, defVal);
        }

        public static T ResolveClass<T>(Dictionary<string, object> dc, string name) where T : class
        {
            object x;
            if (dc.Keys.Contains(name))
                x = JsonConvert.DeserializeObject<T>(dc[name]?.ToString());
            else
                x = null;
            return (T)x;
        }

        private static object CTString(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? dc[name]?.ToString() : defVal;
        }

        private static object CTInt(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToInt32(dc[name] ?? defVal) : defVal;
        }

        private static object CTLong(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToInt64(dc[name] ?? defVal) : defVal;
        }

        private static object CTFloat(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToSingle(dc[name] ?? defVal) : defVal;
        }

        private static object CTDouble(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToDouble(dc[name] ?? defVal) : defVal;
        }

        private static object CTDecimal(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToDecimal(dc[name] ?? defVal) : defVal;
        }

        private static object CTByte(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToByte(dc[name] ?? defVal) : defVal;
        }

        private static object CTBool(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToBoolean(dc[name] ?? defVal) : defVal;
        }

        private static object CTDateTime(Dictionary<string, object> dc, string name, object defVal)
        {
            return dc.Keys.Contains(name) ? Convert.ToDateTime(dc[name] ?? defVal) : defVal;
        }

        #endregion 字典值转换
    }
}